﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;
using System.Net;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace Pittypat.Web
{
    /// <summary>
    /// 处理与用户有关的功能，比如用户信息、登录、注销等。
    /// </summary>
    static class UserHttpHandler
    {
        // 删除用户令牌的日期时间。
        static readonly DateTime CookieDeleteTime = new DateTime(1900, 1, 1);

        /// <summary>
        /// 异步处理指定的请求。
        /// </summary>
        /// <param name="request">要处理的请求。</param>
        /// <returns>结果消息。</returns>
        internal static async Task<Message> ProcessAsync(Request request)
        {
            // 获取当前用户验证服务
            var authService = AuthorityService.Current;

            if (authService == null)
            {
                // 没有提供有效的验证服务
                return Message.Create("没有提供有效的用户账号服务，请检查配置文件的 authorityService 配置项目。\r\n这是一个配置错误，需要系统管理人员调整配置文件。");
            }

            // 当前请求的路径，已经去掉了 AppPath
            var path = request.LowerAbsPath;

            if (path == "/user/info")
            {
                // 获取当前用户信息
                return await ProcessUserInfoAsync(request, authService);
            }
            else if (path == "/user/login")
            {
                // 登录
                return await ProcessLoginAsync(request, authService);
            }
            else if (path == "/user/logout")
            {
                // 注销
                return await ProcessLogoutAsync(request, authService);
            }
            else if (path == "/user/navlist")
            {
                // 加载用户的新通知列表
                return await ProcessNavListAsync(request, authService);
            }

            // 不受支持的请求路径
            return Message.Create(HttpStatusCode.NotFound);
        }

        // 加载用户信息
        static async Task<Message> ProcessUserInfoAsync(Request request, IAuthorityService authService)
        {
            // 当前用户的用户令牌
            var userToken = request.UserToken;
            // 初始化用户信息为匿名用户
            var user = User.Anonymous;

            if (!string.IsNullOrEmpty(userToken))
            {
                // 传递功能路径为空字符串表示仅仅查询用户信息，而不是执行权限验证
                var permission = await authService.DemandAsync(SystemTokenProvider.Current.GetSystemToken(), userToken, "" /* funcPath */, request.Progress);
                if (permission != null)
                {
                    // 查询到了用户信息，请注意，查询到的用户信息仍然可能为匿名用户，也就是 Id 可能为 null
                    user = permission.User;
                }
            }

            return Message.Create(user);
        }

        // 登录
        static async Task<Message> ProcessLoginAsync(Request request, IAuthorityService authService)
        {
            // 登录名称
            string name = request.Form["name"];
            // 登录密码
            string password = request.Form["password"];
            
            if (string.IsNullOrEmpty(name))
            {
                // 没有提供登录名称
                return Message.Create("没有提供用户登录名称。");
            }

            if (string.IsNullOrEmpty(password))
            {
                // 没有提供登录密码
                return Message.Create("没有提供用户登录密码。");
            }

            // 进行登录验证
            var result = await authService.LoginAsync(SystemTokenProvider.Current.GetSystemToken(), name, password, request.Progress) ?? LoginResult.Anonymous;
            // 如果登录成功，则返回的用户令牌不应该是 null 或空字符串
            var token = result.Token;

            // 返回给客户端的消息
            var msg = new ValueMessage(result);

            if (result.IsAnonymous)
            {
                // 删除用户令牌的 cookie
                msg.Cookies.Add(new CookieHeaderValue(Request.UserTokenName, "")
                {
                    Expires = CookieDeleteTime,
                    HttpOnly = true,
                    Path = "/"
                });
            }
            else if (token.Length > 1)
            {
                // 检查客户端是否启用了 cookie，如果启用了 cookie，则将用户令牌分为两个部分
                var cookieEnabled = false;

                // 客户端是否启用了 cookie 的指示由客户端主送发送到服务器，参数名称为 __cookie_enabled，如果没有提供该参数，认为客户端没有启用 cookie
                if (!bool.TryParse(request.Form["__cookie_enabled"], out cookieEnabled))
                {
                    cookieEnabled = false;
                }

                if (cookieEnabled)
                {
                    // 当客户端启用了 cookie 时，将用户令牌拆分为两个部分，分别保存在 localStorage 和 cookie 中

                    // storage 保存前半部分
                    result.Token = (@string)token.Substring(0, token.Length / 2);

                    // cookie 保存后半部分
                    msg.Cookies.Add(new CookieHeaderValue(Request.UserTokenName, token.Substring(token.Length / 2))
                    {
                        HttpOnly = true,
                        Path = "/"
                    });
                }
            }
            
            return msg;
        }

        // 注销
        static async Task<Message> ProcessLogoutAsync(Request request, IAuthorityService authService)
        {
            // 当前用户的令牌
            var userToken = request.UserToken;

            if (!string.IsNullOrEmpty(userToken))
            {
                // 执行注销
                await authService.LogoutAsync(SystemTokenProvider.Current.GetSystemToken(), userToken, request.Progress);
            }

            var msg = Message.Create();

            // 删除用户令牌的 cookie
            msg.Cookies.Add(new CookieHeaderValue(Request.UserTokenName, "")
            {
                Expires = CookieDeleteTime,
                HttpOnly = true,
                Path = "/"
            });

            return msg;
        }

        // 获取用户的新通知列表
        static async Task<Message> ProcessNavListAsync(Request request, IAuthorityService authService)
        {
            // 当前用户的令牌
            var userToken = request.UserToken;
            // 导航列表默认为空列表
            var list = NavList.Empty;

            if (!string.IsNullOrEmpty(userToken))
            {
                // 加载导航列表
                list = await authService.NavListAsync(SystemTokenProvider.Current.GetSystemToken(), userToken, request.Progress) ?? NavList.Empty;
            }
            
            // 返回导航列表
            return Message.Create(list ?? NavList.Empty);
        }
    }
}
